#include "smart_pointer.h"

template <typename T>
SmartPointer<T>::SmartPointer(T *ptr)
{
    _ptr = ptr;
}

template <typename T>
SmartPointer<T>::~SmartPointer()
{
    delete _ptr;
    std::cout << "delete pa" << std::endl;
}

template <typename T>
AutoPointer<T>::AutoPointer(T *ptr)
    : _ptr(ptr)
{
}

template <typename T>
AutoPointer<T>::AutoPointer(AutoPointer<T> &ap)
{
    _ptr = ap._ptr;
    ap._ptr = nullptr;
}

template <typename T>
AutoPointer<T> &AutoPointer<T>::operator=(AutoPointer<T> &ap)
{
    _ptr = ap._ptr;
    ap._ptr = nullptr;
}

template <typename T>
AutoPointer<T>::~AutoPointer()
{
    if (_ptr != nullptr)
    {
        delete _ptr;
    }
    else
    {
        std::cout << "_ptr is nullptr!" << std::endl;
    }
}

template <typename T>
T &AutoPointer<T>::operator*()
{
    return *_ptr;
}

template <typename T>
T &AutoPointer<T>::operator->()
{
    return *_ptr;
}

template <typename T>
UniquePointer<T>::UniquePointer(T *ptr)
    : _ptr(ptr)
{
}

template <typename T>
T &UniquePointer<T>::operator->()
{
    return *_ptr;
}

template <typename T>
T &UniquePointer<T>::operator*()
{
    return *_ptr;
}

template <typename T>
UniquePointer<T>::~UniquePointer()
{
    if (_ptr != nullptr)
    {
        delete _ptr;
    }
    else
    {
        std::cout << "_ptr is nullptr!" << std::endl;
    }
}

template <typename T>
SharedPointer<T>::SharedPointer(T *ptr)
    : _ptr(ptr), _pMutex(new std::mutex)
{
    _pCount = new int(0);
    AddRef();
}

template <typename T>
T *SharedPointer<T>::operator->()
{
    return _ptr;
}

template <typename T>
T &SharedPointer<T>::operator*()
{
    return *_ptr;
}

template <typename T>
SharedPointer<T>::~SharedPointer()
{
    Release();
}

template <typename T>
void SharedPointer<T>::AddRef()
{
    _pMutex->lock();
    ++(*_pCount);
    _pMutex->unlock();
}

template <typename T>
void SharedPointer<T>::SubRef()
{
    _pMutex->lock();
    --(*_pCount);
    _pMutex->unlock();
}

template <typename T>
SharedPointer<T>::SharedPointer(SharedPointer<T> &sp)
    : _pCount(sp._pCount), _ptr(sp._ptr), _pMutex(sp._pMutex)
{
    AddRef();
}

template <typename T>
T *SharedPointer<T>::get() const
{
    return _ptr;
}

template <typename T>
SharedPointer<T> &SharedPointer<T>::operator=(SharedPointer<T> &sp)
{
    if (_ptr != sp._ptr)
    {
        Release();
        _ptr = sp._ptr;
        _pCount = sp._pCount;
        _pMutex = sp._pMutex;
        sp.AddRef();
    }

    return *this;
}

template <typename T>
void SharedPointer<T>::Release()
{
    // 打印引用计数的次数
    // std::cout << "_count: " << (*_pCount) << std::endl;
    SubRef();
    if ((*_pCount) == 0 && _ptr != nullptr)
    {
        delete _ptr;
        delete _pCount;
        delete _pMutex;

        _ptr = nullptr;
        _pCount = nullptr;
        _pMutex = nullptr;
    }
}

template <typename T>
int SharedPointer<T>::use_count() const
{
    return *_pCount;
}

Student::Student(std::string name = static_cast<std::string>("张三"), int age = 10, std::string sex = static_cast<std::string>("男"))
    : _name(name), _age(age), _sex(sex)
{
}

Student ::~Student()
{
    std::cout << "Student ::~Student()" << std::endl;
}

template <typename T>
WeakPointer<T>::WeakPointer(T *ptr)
    : _ptr(ptr)
{
}

template <typename T>
T *WeakPointer<T>::operator->()
{
    return _ptr;
}

template <typename T>
T &WeakPointer<T>::operator*()
{
    return *_ptr;
}

template <typename T>
WeakPointer<T>::WeakPointer(const SharedPointer<T> &sp)
    : _ptr(sp.get())
{
}

template <typename T>
WeakPointer<T> &WeakPointer<T>::operator=(const WeakPointer<T> &wp)
{
    if (wp._ptr != _ptr)
    {
        _ptr = wp._ptr;
    }

    return *this;
}